package com.yunc.modules.sys.controller;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sun.management.OperatingSystemMXBean;
import com.yunc.base.exception.UCException;
import com.yunc.base.security.UserEntity;
import com.yunc.base.service.RedisService;
import com.yunc.base.utils.*;
import com.yunc.modules.sys.entity.SysMessage;
import com.yunc.modules.sys.entity.SysRole;
import com.yunc.modules.sys.entity.SysUser;
import com.yunc.modules.sys.entity.SysUserRole;
import com.yunc.modules.sys.entity.vo.SysMessageSearchVO;
import com.yunc.modules.sys.service.ISysMessageService;
import com.yunc.modules.sys.service.ISysRoleService;
import com.yunc.modules.sys.service.ISysUserRoleService;
import com.yunc.modules.sys.service.ISysUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotEmpty;
import java.lang.management.ManagementFactory;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 用户管理
 *
 * @author taocongcong
 * @create 2017-12-15 13:50
 */
@Api(tags = "用户管理")
@Slf4j
@RestController
@RequestMapping("/sysUser")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class SysUserController {

    private static final String AUTH_TOKEN = "auth_user_";

    @Value("${single.login:false}")
    private Boolean singleLogin;

    private final ISysUserService sysUserService;
    private final ISysUserRoleService sysUserRoleService;
    private final ISysRoleService sysRoleService;
    private final ISysMessageService sysMessageService;
    private final RedisService redisService;
    private final AuthenticationManager authenticationManager;
    private final BCryptPasswordEncoder encoder;

    @PostMapping(value = "/login")
    // @Limit(key = "login", period = 1, count = 10, name = "loginLimit", prefix = "limit")
    public R updatePassword(HttpServletRequest request, SysUser sysUser) {
        Authentication authentication = null;
        try {
            authentication = authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(sysUser.getLoginName(), sysUser.getUserPassword(), new ArrayList<>()));
        } catch (Exception e) {
            if (e instanceof UsernameNotFoundException) {
                throw new UCException(BaseConstant.LOGIN_ERROR_NOID);
            } else if (e instanceof BadCredentialsException) {
                throw new UCException(BaseConstant.LOGIN_ERROR_PSW);
            }
        }
        // 所以就是JwtUser啦
        UserEntity jwtUser = (UserEntity) authentication.getPrincipal();
        // System.out.println("jwtUser:" + jwtUser.toString());
        String token = JwtTokenUtils.createToken(String.valueOf(jwtUser.getUserId()), false);
        // 需要传递user数据
        String userId = jwtUser.getUserId();
        // 登录日志
        LoginLogUtils.loginLog(request, BaseConstant.LOGIN_SUCCESS, BaseConstant.SuccessErrorStatus.SUCCESS.getValue());
        // 保存到redis
        if (singleLogin) {
            // 删除之前的登录信息
            redisService.del(AUTH_TOKEN + userId);
        }
        redisService.hset(AUTH_TOKEN + userId, token, jwtUser, 21600L);
        return R.ok().put("token", token)
                .put("userId", userId)
                .put("headLogo", jwtUser.getHeadLogo());
    }

    /**
     * 获取用户列表
     */
    @GetMapping("/page")
    @ApiOperation(value = "获取用户列表")
    @PreAuthorize("@ss.hasPermi('sys:user:list')")
    public R page(Page<SysUser> page, SysUser sysUser) {
        Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        if (principal instanceof UserDetails) {
            System.out.println(principal);
        }
        Object principal1 = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        if (principal1 instanceof UserDetails) {
            System.out.println(principal);
        }
        IPage<SysUser> sysUserPage = sysUserService.pageInfo(page, sysUser);
        return R.ok().put("data", sysUserPage.getRecords()).put("count", sysUserPage.getTotal());
    }

    @RequestMapping("/user")
    public Principal user(Principal user) {
        return user;
    }

    /**
     * 根据登录名获取用户
     */
    @GetMapping("/getByLoginName")
    public SysUser getByLoginName(String loginName) {
        return sysUserService.getByLoginName(loginName);
    }

    /**
     * 获取当前用户信息
     */
    @GetMapping("/info")
    public R getCurrentUser() {
        String userId = SecurityUtils.getUserId();
        SysUser byId = sysUserService.getById(userId);
        return R.ok().put("sysUser", byId);
    }

    /**
     * 获取所有角色和权限
     */
    @GetMapping("/queryUserMenuPermsList")
    @PreAuthorize("@ss.hasPermi('sys:user:list')")
    public List<String> queryUserMenuPermsList(String userId) {
        // 获取所有权限
        List<String> permissions = sysUserService.queryUserMenuPermsList(userId);
        return permissions;
    }

    @GetMapping("/list")
    @PreAuthorize("@ss.hasPermi('sys:user:list')")
    public R list(SysUser sysUser) {
        List<SysUser> sysUserList = sysUserService.list(new QueryWrapper<>(sysUser));
        return R.ok().put("sysUserList", sysUserList);
    }

    @GetMapping("/view")
    @Cacheable(value = "user-key", key = "#userId+'view'")
    public SysUser view(String userId) {
        SysUser sysUser = sysUserService.getById(userId);
        log.info("在{}查询用户，主键是：{}", DateUtil.formatDateTime(new Date()), userId);
        return sysUser;
    }

    @GetMapping("/userInfo")
    public R info(@RequestParam(required = false) String userId) {
        SysUser sysUser = sysUserService.getById(userId);
        // 获取用户角色
        List<SysUserRole> userRoleList = new ArrayList<>();
        if (userId != null) {
            SysUserRole roleRecord = new SysUserRole();
            roleRecord.setUserId(userId);
            QueryWrapper<SysUserRole> ew = new QueryWrapper<>(roleRecord);
            userRoleList = sysUserRoleService.list(ew);
        }
        // 获取所有角色
        List<SysRole> sysRoleList = sysRoleService.list(new QueryWrapper<>());
        return R.ok().put("sysUser", sysUser).put("sysRoleList", sysRoleList).put("userRoleList", userRoleList);
    }

    /**
     * 判断登录名是否唯一
     */
    @GetMapping("/checkUnique")
    public R checkUnique(Long userId, @NotEmpty(message = "登录名不能为空") String loginName) {
        String recordName = "";
        if (userId != null && userId != 0) {
            SysUser user = sysUserService.getById(userId);
            recordName = user.getLoginName();
        }
        QueryWrapper<SysUser> ew = new QueryWrapper<>();
        ew.eq("login_name", loginName);
        SysUser sysUser = sysUserService.getOne(ew);
        if (sysUser != null) {
            if (StringUtils.isNotEmpty(recordName) && StringUtils.equals(loginName, recordName)) {
                return R.ok();
            }
            return R.error("您输入的登录名重复");
        }
        return R.ok();
    }

    /**
     * 判断输入的密码是否正确
     */
    @GetMapping("/checkPassword")
    public R checkPassword(@NotEmpty(message = "密码不能为空") String password) {
        String userId = SecurityUtils.getUserId();
        SysUser sysUser = sysUserService.getById(userId);
        if (sysUser == null) {
            return R.error("未查询到当前用户，请重新登录");
        }
        if (!StringUtils.equals(DigestUtil.md5Hex(password), sysUser.getUserPassword())) {
            return R.error("密码输入错误");
        }
        return R.ok();
    }

    @PutMapping(value = "/updatePassword")
    public R updatePassword(@NotEmpty(message = "密码不能为空") String password) {
        String userId = SecurityUtils.getUserId();
        SysUser sysUser = sysUserService.getById(userId);
        if (sysUser == null) {
            return R.error("未查询到当前用户，请重新登录");
        }
        String pwd = DigestUtil.md5Hex(password);
        sysUser.setUserPassword(pwd);
        boolean flag = sysUserService.updateById(sysUser);
        if (!flag) {
            return R.error();
        }
        // 删除之前的登录信息
        redisService.del(AUTH_TOKEN + userId);
        return R.ok();
    }

    /**
     * 保存
     */
    @PostMapping("/save")
    @CacheEvict(value = {"user-dept-tree-key", "sysUserRoleMenus"}, allEntries = true)
    @PreAuthorize("@ss.hasPermi('sys:user:save')")
    public R save(SysUser user) {
        R r = sysUserService.saveUser(user);
        if ((int) r.get("code") != 0) {
            return r;
        }
        // 删除之前的登录信息
        // redisService.del(AUTH_TOKEN + user.getId());
        return r;
    }

    /**
     * 修改
     */
    @PutMapping(value = "/update")
    @CacheEvict(value = {"user-dept-tree-key", "sysUserRoleMenus"}, allEntries = true)
    @PreAuthorize("@ss.hasPermi('sys:user:update')")
    public R update(SysUser user) {
        R r = sysUserService.updateUser(user);
        if ((int) r.get("code") != 0) {
            return r;
        }
        // 删除之前的登录信息
        // redisService.del(AUTH_TOKEN + user.getId());
        return r;
    }

    /**
     * 修改基本信息，姓名、头像
     */
    @PutMapping(value = "/updateBasic")
    public R updateBasic(SysUser user) {
        String userId = SecurityUtils.getUserId();
        SysUser sysUser = sysUserService.getById(userId);
        sysUser.setUserName(user.getUserName());
        sysUser.setHeadLogo(user.getHeadLogo());
        boolean flag = sysUserService.updateById(sysUser);
        if (!flag) {
            return R.error();
        }
        return R.ok();
    }

    /**
     * 重置密码
     */
    @PutMapping(value = "/resetPassword")
    public R resetPassword(String userId, @RequestParam(required = false) String userPassword,
                    @RequestParam(required = false) String sid) {
        SysUser sysUser = new SysUser();
        sysUser.setId(userId);
        if (StringUtils.isEmpty(userPassword)) {
            userPassword = BaseConstant.DEFAULT_PASSWORD;
        }
        String encode = encoder.encode(userPassword);
        sysUser.setUserPassword(encode);
        boolean flag = sysUserService.updateById(sysUser);
        if (!flag) {
            return R.error();
        }
        // 删除之前的登录信息
        redisService.del(AUTH_TOKEN + userId);
        return R.ok();
    }

    /**
     * 系统信息
     */
    @GetMapping("/systemInfo")
    public R getSystemInfo() {
        // 用户总人数，总消息数，当天总消息，个人消息，当天个人消息
        QueryWrapper<SysUser> qw = new QueryWrapper<>();
        qw.eq("remove_tag", BaseConstant.REMOVE_N);
        int count = sysUserService.count(qw);
        int dayCount = sysMessageService.getDayCount();
        String userId = SecurityUtils.getUserId();
        int dayCountUser = sysMessageService.getDayCountUser(userId);
        // 消息
        Page<SysMessage> page = new Page<>();
        // page.setDesc("create_time");
        page.setCurrent(0);
        page.setSize(8);
        SysMessageSearchVO sysMessage = new SysMessageSearchVO();
        sysMessage.setStatus("1");
        sysMessage.setUserId(userId);
        List<SysMessage> sysMessageList = sysMessageService.pageInfo(page, sysMessage);
        String osName = System.getProperty("os.name");
        OperatingSystemMXBean osmxb = (OperatingSystemMXBean) ManagementFactory
                .getOperatingSystemMXBean();
        double systemCpuLoad = osmxb.getSystemCpuLoad();
        int kb = 1024;
        String cpuLoad = NumberUtil.roundStr(systemCpuLoad * 100, 2);
        // 已使用的物理内存
        long usedMemory = (osmxb.getTotalPhysicalMemorySize() - osmxb.getFreePhysicalMemorySize()) / kb;
        long totalMemorySize = osmxb.getTotalPhysicalMemorySize() / kb;
        double memory = NumberUtil.div(usedMemory, totalMemorySize);
        String memoryLoad = NumberUtil.roundStr(memory * 100, 2);
        return R.ok().put("osName", osName).put("cpuLoad", cpuLoad)
                .put("memoryLoad", memoryLoad).put("count", count)
                .put("dayCount", dayCount).put("dayCountUser", dayCountUser)
                .put("messageList", sysMessageList);
    }
}
